package com.platform.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.platform.common.bean.BaseException;
import com.platform.common.bean.SystemConfigBean;
import com.platform.common.menus.ResultCodeEnum;
import com.platform.common.menus.SysConfigEnum;
import com.platform.helper.bean.MapperUtil;
import com.platform.system.entity.*;
import com.platform.system.mapper.SysUserGroupMapper;
import com.platform.system.service.*;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.stream.Collectors;

/**
 * describe:
 *
 * @author rainly
 * @date 2019/12/06
 * @time 11:31 下午
 */
@Slf4j
@Service
public class SysUserGroupServiceImpl extends ServiceImpl<SysUserGroupMapper, SysUserGroup> implements SysUserGroupService {

    @Resource
    private SysUserGroupRoleService sysUserGroupRoleService;

    @Resource
    private SysUserRoleService sysUserRoleService;

    @Resource
    private SysUserGroupUserService sysUserGroupUserService;

    @Resource
    private SysRoleExcludeService sysRoleExcludeService;

    @Resource
    private SysRoleService sysRoleService;

    /**
     * 用户组增加角色，用户组下面的用户同时增加角色
     *
     * @param sysUserGroupRole 用户组角色
     */

    @Override
    public void addRole(SysUserGroupRole sysUserGroupRole) {
        if (StringUtils.isNotEmpty(sysUserGroupRole.getRoleId()) && StringUtils.isNotEmpty(sysUserGroupRole.getUserGroupId())) {
            isPlatformManager(sysUserGroupRole.getRoleId(), sysUserGroupRole.getUserGroupId(), null);
            checkExcludeRole(sysUserGroupRole);

            //1、增加用户组角色关联表
            boolean isSave = sysUserGroupRoleService.save(sysUserGroupRole);
            if (!isSave) {
                log.error("新增用户组角色关联表失败", sysUserGroupRole.toString());
                throw new BaseException(ResultCodeEnum.FAILURE);
            }
            //2、查询用户组下的所有用户
            List<SysUserGroupUser> sysUserGroupUsers = sysUserGroupUserService.list(
                    new LambdaQueryWrapper<SysUserGroupUser>()
                            .eq(SysUserGroupUser::getUserGroupId, sysUserGroupRole.getUserGroupId())
            );

            if (!CollectionUtils.isEmpty(sysUserGroupUsers)) {
                //3、用户组下的用户增加角色(增加用户角色关联表)
                List<SysUserRole> sysUserRoles = new ArrayList<>(sysUserGroupUsers.size());
                SysUserRole sysUserRole = new SysUserRole();
                sysUserRole.setRoleId(sysUserGroupRole.getRoleId());
                for (SysUserGroupUser sysUserGroupUser : sysUserGroupUsers) {
                    SysUserRole dumpCloneSysUserRole = MapperUtil.map(sysUserRole, SysUserRole.class);
                    dumpCloneSysUserRole.setUserId(sysUserGroupUser.getUserId());
                    sysUserRoles.add(dumpCloneSysUserRole);
                }
                boolean saveBatch = sysUserRoleService.saveBatchByUserGroup(sysUserRoles);
                if (!saveBatch) {
                    log.error("新增用户角色关联表失败", sysUserRoles.toString());
                    throw new BaseException(ResultCodeEnum.FAILURE);
                }
            }
        } else {
            log.error("新增用户组角色关联表失败", sysUserGroupRole.toString());
            throw new BaseException(ResultCodeEnum.PARAM_IS_INACTIVE);
        }
    }

    /**
     * 用户组增加角色，用户组下面的用户同时增加角色
     *
     * @param roleId      角色id
     * @param userGroupId 用户组id
     */
    @Override
    public void addRole(@NonNull String roleId, @NonNull String userGroupId) {
        SysUserGroupRole sysUserGroupRole = new SysUserGroupRole();
        sysUserGroupRole.setRoleId(roleId);
        sysUserGroupRole.setUserGroupId(userGroupId);
        addRole(sysUserGroupRole);
    }

    /**
     * 用户组删除角色，用户组下面的用户同时删除角色
     *
     * @param sysUserGroupRole 用户组角色
     */
    @Override
    public void removeRole(SysUserGroupRole sysUserGroupRole) {
        if (StringUtils.isNotEmpty(sysUserGroupRole.getId())) {
            //1、查用户组与角色关联表,获得用户组id
            sysUserGroupRole = sysUserGroupRoleService.getById(sysUserGroupRole.getId());
            //2、删除用户组与角色关联表
            boolean isRemove = sysUserGroupRoleService.removeById(sysUserGroupRole.getId());

            if (!isRemove) {
                log.error("删除用户组与角色关联表失败", sysUserGroupRole);
                throw new BaseException(ResultCodeEnum.FAILURE);
            }
            //3、根据用户组id查询，用户组下的用户
            List<SysUserGroupUser> sysUserGroupUsers = sysUserGroupUserService.list(
                    new LambdaQueryWrapper<SysUserGroupUser>()
                            .eq(SysUserGroupUser::getUserGroupId, sysUserGroupRole.getUserGroupId())
            );

            //4、根据用户id，和角色id，删除用户角色关联表的相关记录
            if (!CollectionUtils.isEmpty(sysUserGroupUsers)) {
                for (SysUserGroupUser sysUserGroupUser : sysUserGroupUsers) {
                    boolean remove = sysUserRoleService.remove(
                            new LambdaQueryWrapper<SysUserRole>()
                                    .eq(SysUserRole::getUserId, sysUserGroupUser.getUserId())
                                    .eq(SysUserRole::getRoleId, sysUserGroupRole.getRoleId())
                    );
                    if (!remove) {
                        log.error("删除用户角色关联表失败", "user_id: " + sysUserGroupUser.getUserId() + " role_id: " + sysUserGroupRole.getRoleId());
                        throw new BaseException(ResultCodeEnum.FAILURE);
                    }
                }
            }
        } else {
            log.error("删除用户角色关联表失败", sysUserGroupRole.toString());
            throw new BaseException(ResultCodeEnum.PARAM_IS_INACTIVE);
        }
    }

    /**
     * 用户组删除角色，用户组下面的用户同时删除角色
     *
     * @param sysUserGroupRoleId 用户组角色关联表id
     */
    @Override
    public void removeRole(@NonNull String sysUserGroupRoleId) {
        SysUserGroupRole sysUserGroupRole = new SysUserGroupRole();
        sysUserGroupRole.setId(sysUserGroupRoleId);
        removeRole(sysUserGroupRole);
    }

    /**
     * 用户组增加用户，用户组下面的新用户同时增加角色
     *
     * @param sysUserGroupUser 用户组用户
     */
    @Override
    public void addUser(SysUserGroupUser sysUserGroupUser) {
        if (StringUtils.isNotEmpty(sysUserGroupUser.getUserId()) && StringUtils.isNotEmpty(sysUserGroupUser.getUserGroupId())) {
            isPlatformManager(null, sysUserGroupUser.getUserGroupId(), sysUserGroupUser.getUserId());
            checkExcludeUser(sysUserGroupUser);

            //1、用户组添加用户
            boolean isSave = sysUserGroupUserService.save(sysUserGroupUser);
            if (!isSave) {
                log.error("新增用户组角色关联表失败", sysUserGroupUser.toString());
                throw new BaseException(ResultCodeEnum.FAILURE);
            }
            //2、查询用户组与角色关联表
            List<SysUserGroupRole> sysUserGroupRoles = sysUserGroupRoleService.list(
                    new LambdaQueryWrapper<SysUserGroupRole>()
                            .eq(SysUserGroupRole::getUserGroupId, sysUserGroupUser.getUserGroupId())
            );
            if (!CollectionUtils.isEmpty(sysUserGroupRoles)) {
                //3、用户组下的用户增加角色(增加用户角色关联表)
                List<SysUserRole> sysUserRoles = new ArrayList<>(sysUserGroupRoles.size());
                SysUserRole sysUserRole = new SysUserRole();
                sysUserRole.setUserId(sysUserGroupUser.getUserId());
                for (SysUserGroupRole sysUserGroupRole : sysUserGroupRoles) {
                    SysUserRole dumpCloneSysUserRole = MapperUtil.map(sysUserRole, SysUserRole.class);
                    dumpCloneSysUserRole.setRoleId(sysUserGroupRole.getRoleId());
                    sysUserRoles.add(dumpCloneSysUserRole);
                }
                boolean saveBatch = sysUserRoleService.saveBatchByUserGroup(sysUserRoles);
                if (!saveBatch) {
                    log.error("新增用户角色关联表失败", sysUserRoles.toString());
                    throw new BaseException(ResultCodeEnum.FAILURE);
                }
            }
        } else {
            log.error("新增用户组用户关联表失败", sysUserGroupUser.toString());
            throw new BaseException(ResultCodeEnum.PARAM_IS_INACTIVE);
        }
    }

    /**
     * 用户组增加用户，用户组下面的新用户同时增加角色
     *
     * @param userId      用户id
     * @param userGroupId 用户组id
     */
    @Override
    public void addUser(@NonNull String userId, @NonNull String userGroupId) {
        SysUserGroupUser sysUserGroupUser = new SysUserGroupUser();
        sysUserGroupUser.setUserId(userId);
        sysUserGroupUser.setUserGroupId(userGroupId);
        addUser(sysUserGroupUser);
    }

    /**
     * 用户组删除用户
     *
     * @param sysUserGroupUser 用户组用户
     */
    @Override
    public void removeUser(SysUserGroupUser sysUserGroupUser) {
        if (StringUtils.isNotEmpty(sysUserGroupUser.getUserGroupId())) {
            //1、查询用户组与用户关联表
            sysUserGroupUser = sysUserGroupUserService.getById(sysUserGroupUser.getId());
            if (null != sysUserGroupUser) {
                //2、删除用户组与用户关联表记录
                boolean isRemove = sysUserGroupUserService.removeById(sysUserGroupUser.getId());
                if (!isRemove) {
                    log.error("删除用户组与用户关联表失败", sysUserGroupUser);
                    throw new BaseException(ResultCodeEnum.FAILURE);
                }
                //3、根据用户组id查询用户组与角色关联表
                List<SysUserGroupRole> sysUserGroupRoles = sysUserGroupRoleService.list(
                        new LambdaQueryWrapper<SysUserGroupRole>()
                                .eq(SysUserGroupRole::getUserGroupId, sysUserGroupUser.getUserGroupId())
                );
                //3、用户与角色关联表根据用户id和角色id删除
                if (!CollectionUtils.isEmpty(sysUserGroupRoles)) {
                    for (SysUserGroupRole sysUserGroupRole : sysUserGroupRoles) {
                        boolean remove = sysUserRoleService.remove(
                                new LambdaQueryWrapper<SysUserRole>()
                                        .eq(SysUserRole::getUserId, sysUserGroupUser.getUserId())
                                        .eq(SysUserRole::getRoleId, sysUserGroupRole.getRoleId())
                        );
                        if (!remove) {
                            log.error("删除用户角色关联表失败", "user_id: " + sysUserGroupUser.getUserId() + " role_id: " + sysUserGroupRole.getRoleId());
                            throw new BaseException(ResultCodeEnum.FAILURE);
                        }
                    }
                }
            }
        } else {
            log.error("删除用户组用户关联表失败", sysUserGroupUser.toString());
            throw new BaseException(ResultCodeEnum.PARAM_IS_INACTIVE);
        }
    }

    /**
     * 用户组删除用户
     *
     * @param sysUserGroupUserId 用户组用户关联表id
     */
    @Override
    public void removeUser(@NonNull String sysUserGroupUserId) {
        SysUserGroupUser sysUserGroupUser = new SysUserGroupUser();
        sysUserGroupUser.setId(sysUserGroupUserId);
        removeUser(sysUserGroupUser);
    }

    private void isPlatformManager(String roleId, String userGroupId, String userId) {
        //平台管理员角色 不能再添加到任何用户组
        SysRole platformManagerRole = sysRoleService.selectPlatformRole();
        if (platformManagerRole == null) {
            throw new BaseException(ResultCodeEnum.FAILURE, "平台管理员角色缺少，请联系管理员");
        }
        if (Objects.equals(roleId, platformManagerRole.getRoleId())) {
            throw new BaseException(ResultCodeEnum.FAILURE, "不能添加平台管理员角色");
        }

        //平台管理员 不能再添加到任何用户组
        List<SysUserRole> sysUserRoleList = sysUserRoleService.list(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getRoleId, platformManagerRole.getRoleId()));
        List<String> platformManagers = Optional.ofNullable(sysUserRoleList)
                .map(sysUserRoles -> sysUserRoles.stream().map(SysUserRole::getUserId).collect(Collectors.toList()))
                .orElse(new ArrayList<>());
        if (platformManagers.contains(userId)) {
            throw new BaseException(ResultCodeEnum.FAILURE, "不能添加平台管理员");
        }

        //平台管理员组 不能关联其他用户或角色
        List<SysUserGroupRole> userGroupRoleList = sysUserGroupRoleService.list(
                new LambdaQueryWrapper<SysUserGroupRole>().eq(SysUserGroupRole::getRoleId, platformManagerRole.getRoleId()));
        List<String> platformManagerGroups = Optional.ofNullable(userGroupRoleList)
                .map(sysUserGroupRoles -> sysUserGroupRoles.stream().map(SysUserGroupRole::getUserGroupId).collect(Collectors.toList()))
                .orElse(new ArrayList<>());
        if (platformManagerGroups.contains(userGroupId)) {
            throw new BaseException(ResultCodeEnum.FAILURE, "平台管理员组不能添加角色或用户");
        }

    }

    /**
     * 效验用户组下的角色与新增角色是否存在互斥关系
     *
     * @param sysUserGroupRole sysUserGroupRole
     */
    private void checkExcludeRole(@NotNull SysUserGroupRole sysUserGroupRole) {
        //判断职责分离 是否是静态职责 如果是只需要判断用户组下的角色与新增角色 //动态职责不需要校验角色互斥情况
        if (Objects.equals(SysConfigEnum.SeparationOfDuty.SSD.getValue(), SystemConfigBean.getInstance().getSeparationOfDuty())) {
            //静态职责
            //查询角色互斥表是否有互斥关系的角色
            List<SysRoleExclude> roleExcludeList = sysRoleExcludeService.selectExcludeRoleId(sysUserGroupRole.getRoleId());
            if (CollectionUtils.isNotEmpty(roleExcludeList)) {
                List<String> excludeRoleList = roleExcludeList.stream().map(SysRoleExclude::getRoleId).collect(Collectors.toList());
                //判断角色继承关系 是否是受限继承 如果是只需要判断 用户组的角色与新增角色是否互斥
                if (Objects.equals(SysConfigEnum.RoleInheritance.LIMITED.getValue(), SystemConfigBean.getInstance().getRoleInheritance())) {
                    //受限继承
                    //查询用户组下的角色
                    List<SysUserGroupRole> userGroupRoles = sysUserGroupRoleService.list(
                            new LambdaQueryWrapper<SysUserGroupRole>()
                                    .eq(SysUserGroupRole::getUserGroupId, sysUserGroupRole.getUserGroupId()));
                    List<String> userGroupRoleIds = userGroupRoles.stream().map(SysUserGroupRole::getRoleId).collect(Collectors.toList());

                    if (Collections.disjoint(excludeRoleList, userGroupRoleIds)) {
                        throw new BaseException(ResultCodeEnum.FAILURE, "角色组的角色与新增角色互斥");
                    }
                } else {
                    //一般继承
                    //轮询用户组下的用户的角色 与 新增角色是否互斥
                    List<SysUserGroupUser> userGroupUsers = sysUserGroupUserService.list(new LambdaQueryWrapper<SysUserGroupUser>().eq(SysUserGroupUser::getUserGroupId, sysUserGroupRole.getUserGroupId()));
                    if (CollectionUtils.isNotEmpty(userGroupUsers)) {
                        for (SysUserGroupUser userGroupUser : userGroupUsers) {
                            List<SysUserRole> userRoles = sysUserRoleService.list(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, userGroupUser.getUserId()));
                            if (CollectionUtils.isEmpty(userRoles)) {
                                continue;
                            }
                            List<String> userRoleIds = userRoles.stream().map(SysUserRole::getRoleId).collect(Collectors.toList());
                            if (Collections.disjoint(excludeRoleList, userRoleIds)) {
                                throw new BaseException(ResultCodeEnum.FAILURE, "角色组的角色与新增角色互斥");
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 效验用户组下的角色与新增用户下的角色是否存在互斥关系
     *
     * @param sysUserGroupUser sysUserGroupUser
     */
    private void checkExcludeUser(@NotNull SysUserGroupUser sysUserGroupUser) {
        //1、查询用户组下的角色
        List<SysUserGroupRole> userGroupRoles = sysUserGroupRoleService.list(
                new LambdaQueryWrapper<SysUserGroupRole>()
                        .eq(SysUserGroupRole::getUserGroupId, sysUserGroupUser.getUserGroupId()));

        List<String> userGroupRoleIds = Optional.ofNullable(userGroupRoles)
                .map(ugrs -> ugrs.stream().map(SysUserGroupRole::getRoleId).collect(Collectors.toList()))
                .orElse(new ArrayList<>());

        //2、查询用户的角色
        List<SysUserRole> userRoles = sysUserRoleService.list(
                new LambdaQueryWrapper<SysUserRole>()
                        .eq(SysUserRole::getUserId, sysUserGroupUser.getUserId()));
        List<String> userRoleIds = Optional.ofNullable(userRoles)
                .map(uris -> uris.stream().map(SysUserRole::getRoleId).collect(Collectors.toList()))
                .orElse(new ArrayList<>());

        //3、效验 是否是受限继承 如果是 则要判断 用户角色是否包含在用户组下的角色里
        if (Objects.equals(SysConfigEnum.RoleInheritance.LIMITED.getValue(), SystemConfigBean.getInstance().getRoleInheritance())) {
            //受限继承
            //效验 如果用户组角色为空，用户角色也必须为空，如果角色组角色不为空，用户角色没要求
            boolean isCheck = (CollectionUtils.isNotEmpty(userGroupRoles) && CollectionUtils.isNotEmpty(userRoles)) || CollectionUtils.isNotEmpty(userGroupRoles);
            if (!isCheck) {
                throw new BaseException(ResultCodeEnum.FAILURE, "受继承关系(受限继承)限制，用户组下的角色必须包含用户的角色");
            }
            //判断用户组角色是否包含新用户的角色
            if (!userGroupRoleIds.containsAll(userRoleIds)) {
                throw new BaseException(ResultCodeEnum.FAILURE, "受继承关系(受限继承)限制，用户组下的角色必须包含用户的角色");
            }
        } else {
            //一般继承
            //4、如果是一般继承关系判断职责关系 //动态职责不需要校验角色互斥情况
            if (Objects.equals(SysConfigEnum.SeparationOfDuty.SSD.getValue(), SystemConfigBean.getInstance().getSeparationOfDuty())) {
                //静态职责
                userGroupRoleIds.removeAll(userRoleIds);
                if (CollectionUtils.isNotEmpty(userGroupRoleIds) && CollectionUtils.isNotEmpty(userRoleIds)) {
                    //两个临时list的意义是用，短的进行查询，与长的匹配，减少数据查询次数
                    List<String> temp;
                    List<String> temp2;
                    if (userGroupRoleIds.size() > userRoleIds.size()) {
                        temp = userRoleIds;
                        temp2 = userGroupRoleIds;
                    } else {
                        temp = userGroupRoleIds;
                        temp2 = userRoleIds;
                    }
                    for (String roleId : temp) {
                        List<SysRoleExclude> sysRoleExcludes = sysRoleExcludeService.selectExcludeRoleId(roleId);
                        if (CollectionUtils.isEmpty(sysRoleExcludes)) {
                            continue;
                        }
                        Optional<SysRoleExclude> isExclude = sysRoleExcludes.stream().filter(sRoleExclude -> temp2.contains(sRoleExclude.getRoleId())).findFirst();
                        if (isExclude.isPresent()) {
                            //存在互斥
                            throw new BaseException(ResultCodeEnum.FAILURE, "角色组的角色与新增用户角色互斥");
                        }
                    }
                }
            }
        }
    }
}
